#include "stdafx.h"
#include <fstream>
#include <string>
#include <map>

HSDialogReply::HSDialogReply()
{
	sReplyText = "";
	sVisibilityCondition = "";
	sOnSelectAction = "";
	sNextPrompt = "";
}

bool HSDialogReply::IsAvailable()
{
	if ( sVisibilityCondition == "always" )
	{
		return true;
	}

	return false;
}

bool HSDialogReply::DoOnSelectAction()
{
	return true;
}

HSDialogScreen::HSDialogScreen()
{
	sId = "";	
	sPrompt = "";
}

HSDialog* HSDialog::sDialog = NULL;

HSDialog& HSDialog::GetInstance()
{
	if ( !sDialog )
	{
		sDialog = new HSDialog();
	}

	return *sDialog;
}

HSDialog::HSDialog()
{
	bActive = false;
	pDialogScreen = NULL;

	aCanvas.SetColor( 0.1f, 0.1f, 0.1f, 1.0f );
	aCanvas.SetSize( HSSettings::fScrW, HSSettings::fScrH );
	aCanvas.SetPosition( HSSettings::fScrW / 2.0f, HSSettings::fScrH / 2.0f );

	float fStep = HSSettings::fScrH / 7.0f;

	taPrompt.SetColor( 1.0f, 0.9f, 0.9f, 1.0f );
	taPrompt.SetPosition( MathUtil::PixelsToWorldUnits(25.0f), 
						  HSSettings::fScrH - fStep );
	taPrompt.SetSize( MathUtil::PixelsToWorldUnits(HSSettings::uiScreenWidth - 50.0f),
					  (2.0f * fStep) / 3.0f );
	taPrompt.SetFont( "fontLarge" );

	for ( unsigned int i = 0; i < 5; i++ )
	{
		taReplies[i].SetColor( 0.9f, 0.9f, 1.0f, 1.0f );
		taReplies[i].SetPosition( MathUtil::PixelsToWorldUnits(25.0f), 
								 HSSettings::fScrH - ((i + 2) * fStep) );
		taReplies[i].SetSize( MathUtil::PixelsToWorldUnits(HSSettings::uiScreenWidth - 50.0f),
							  (2.0f * fStep) / 3.0f );
		taReplies[i].SetFont( "fontLarge" );
	}
}

HSDialog::~HSDialog()
{

}

void HSDialog::MouseMotionEvent(Vec2i screenCoordinates)
{
	if ( !bActive )
	{
		return;
	}

	return;
}

void HSDialog::MouseDownEvent(Vec2i screenCoordinates, MouseButtonInput button)
{
	if ( !bActive )
	{
		return;
	}

	return;
}

void HSDialog::MouseUpEvent(Vec2i screenCoordinates, MouseButtonInput button)
{
	if ( !bActive || !pDialogScreen )
	{
		return;
	}

	Vector2 wCoord = MathUtil::ScreenToWorld( screenCoordinates );

	for ( unsigned int i = 0; i < pDialogScreen->uiValidReplies; i++ )
	{
		if ( !pDialogScreen->reply[i].IsAvailable() )
		{
			continue;
		}

		const BoundingBox& box = taReplies[i].GetBoundingBox();
		
		if ( box.Contains( wCoord ) )
		{
			pDialogScreen->reply[i].DoOnSelectAction();
			ShowDialog( pDialogScreen->reply[i].sNextPrompt );
			return;
		}
	}

	return;
}

void HSDialog::MouseWheelEvent(const Vector2 &scrollOffset)
{
	if ( !bActive )
	{
		return;
	}

	return;
}

void HSDialog::Activate()
{
	if ( bActive )
	{
		return;
	}

	theWorld.Add( &aCanvas, HSDialog::iCanvasLayer );	
	theWorld.Add( &taPrompt, HSDialog::iPromptLayer );	

	for ( unsigned int i = 0; i < 5; i++ )
	{
		theWorld.Add( &taReplies[i], HSDialog::iRepliesLayer );
	}

	bActive = true;
	theCamera.Reset();
	theCamera.SetPosition( HSSettings::fScrW / 2.0f, HSSettings::fScrH / 2.0f );
}

void HSDialog::Deactivate()
{
	if ( !bActive )
	{
		return;
	}

	theWorld.Remove( &aCanvas );
	theWorld.Remove( &taPrompt );
	
	for ( unsigned int i = 0; i < 5; i++ )
	{
		theWorld.Remove( &taReplies[i] );
	}

	bActive = false;
}

HSDialog::HSDialogScreenMap HSDialog::smapDialogs;

bool HSDialog::ShowDialog( const std::string& sDialogId )
{
	if ( sDialogId == "end" )
	{
		Deactivate();
		HSPlayer::GetInstance().Activate();
		HSLevel::GetInstance().Activate();
		return true;
	}

	HSDialogScreenMap::iterator it = smapDialogs.find( sDialogId );

	if ( it == smapDialogs.end() )
	{
		sysLog.Printf( "Cannot find dialog '%s'", sDialogId.c_str() );
		Deactivate();
		HSPlayer::GetInstance().Activate();
		HSLevel::GetInstance().Activate();
		return false;
	}

	pDialogScreen = &it->second;
	taPrompt.SetDisplayString( it->second.sPrompt );
	
	for ( unsigned int i = 0; i < 5; i++ )
	{
		if ( i < it->second.uiValidReplies )
		{
			if ( pDialogScreen->reply[i].IsAvailable() )
			{
				taReplies[i].SetDisplayString( it->second.reply[i].sReplyText );
			}
			else
			{
				taReplies[i].SetDisplayString( "" );
			}
		}
		else
		{
			taReplies[i].SetDisplayString( "" );
		}
	}

	return true;
}

bool HSDialog::LoadDialogs( const std::string& sDialogDefs )
{
	std::ifstream in( "Resources/Data/" + sDialogDefs, std::ifstream::in );

	if ( !in.is_open() )
	{
		sysLog.Printf( "Failed to open %s", sDialogDefs.c_str() );
		return false;
	}

	while ( !in.eof() )
	{
		if ( in.fail() )
		{
			sysLog.Printf( "Failed to parse data from %s", sDialogDefs.c_str() );
			return false;
		}

		// dscreen <id> \n
		// <prompt> \n
		// dreplies [CNT]
		// 
		// [CNT] x
		// <reply>
		// <cond>
		// <onsel>
		// <next>

		std::string sKeyword, sId;
		unsigned int uiCount = 0;
		
		in >> sKeyword >> sId;
		
		if ( sKeyword != "dscreen" )
		{
			if ( in.eof() )
			{
				return true;
			}

			sysLog.Printf( "Failed to parse data, unrecognized token '%s' (expected 'dscreen')", sKeyword.c_str() );
			return false;
		}

		if ( smapDialogs.find( sId ) != smapDialogs.end() )
		{
			sysLog.Printf( "Failed to parse data, dialog '%s' already defined", sId.c_str() );
			return false;
		}

		HSDialogScreen ds;
		ds.sId = sId;

		in.ignore();
		std::getline( in, ds.sPrompt );

		if ( in.fail() )
		{
			sysLog.Printf( "Failed to parse data from %s", sDialogDefs.c_str() );
			return false;
		}

		in >> sKeyword >> ds.uiValidReplies;

		if ( sKeyword != "dreplies" )
		{
			sysLog.Printf( "Failed to parse data, unrecognized token '%s' (expected 'dreplies')", sKeyword.c_str() );
			return false;
		}

		if ( !ds.uiValidReplies )
		{
			sysLog.Printf( "Failed to parse data, at least one reply required for screen '%s'", sId.c_str() );
			return false;
		}

		in.ignore();

		for ( unsigned int i = 0; i < ds.uiValidReplies; i++ )
		{
			std::getline( in, ds.reply[i].sReplyText );
			std::getline( in, ds.reply[i].sVisibilityCondition );
			std::getline( in, ds.reply[i].sOnSelectAction );
			std::getline( in, ds.reply[i].sNextPrompt );

			if ( in.fail() )
			{
				sysLog.Printf( "Failed to parse replz for screen '%s'", sId.c_str() );
				return false;
			}
		}

		smapDialogs[ sId ] = ds;
	}

	return true;
}
